在第8天,我將示範 Vue 3、SvelteKit 與 Angular 如何執行動態的 CSS 類別與樣式綁定。展示中包含 CSS 類別綁定與樣式綁定的範例。當一個項目已購買時,會套用刪除線(strikeout)類別。當項目被標記為高優先時,會使用 priority 類別。加入項目表單中的高優先勾選框被勾選時,字體會因 font-weight
樣式而變粗體 (bold)。
<script setup lang="ts">
import { Icon } from '@iconify/vue'
import { ref, computed } from 'vue'
type Item = { id: number; label: string; highPriority: boolean; purchased: boolean }
const items = ref<Item[]>([])
const togglePurchase = (item: Item) => {
item.purchased = !item.purchased
}
</script>
<template>
<ul>
<div class="list-item" v-for="item in items" :key="item.id">
<li
:class="[{ priority: item.highPriority }, { strikeout: item.purchased }]"
@click="togglePurchase(item)"
>
{{ item.id }} - {{ item.label }}
</li>
</div>
</ul>
</template>
在 Vue 3 中,元素的 CSS 類別可以綁定到陣列或物件。在此範例中,將一個陣列綁定到 <li> 元素的類別。
{ strikeout: item.purchased }
- 當 purchased
屬性為 true 時,strikeout
類別被啟用,否則停用。點擊 <li> 元素時會觸發點擊事件,togglePurchase
函式切換該屬性,導致 strikeout
類別動態套用。
{ priority: item.highPriority }
- 同理,當 highPriority
屬性為 true 時,priority
類別被套用。當使用者勾選 High Priority 框並儲存時,該屬性為 true,文字會以不同顏色呈現。
若要傳入物件做類別綁定,寫法是::class="{ priority: item.highPriority, strikeout: item.purchased }"
<script lang="ts">
import Icon from '@iconify/svelte';
type Item = { id: number; label: string; purchased: boolean; higherPriority: boolean };
let items = $state([] as Item[]);
function togglePurchased(item: Item) {
item.purchased = !item.purchased;
newItem = '';
newItemHigherPriority = false;
}
</script>
<ul>
{#each items as item (item.id)}
<div class="list-item">
<li class={[item.purchased && 'strikeout', item.higherPriority && 'priority']}>{item.id} - {item.label}</li>
<button class="btn" onclick={() => togglePurchased(item)} aria-label="purchase an item">
<Icon icon={!item.purchased ? "ic:baseline-check" : "ic:baseline-close" } />
</button>
</div>
{/each}
</ul>
因為 Svelte 編譯器警告 <li> 不應可點擊,因此改用按鈕觸發 togglePurchase
函式切換 purchased
屬性。
如同 Vue 3,元素的 CSS 類別可綁定陣列或物件。這範例傳入陣列到 <li> 元素的類別。
{ item.purchased && 'strikeout' }
- 若 purchased
為真,strikeout
類別啟用,否則停用。
{ item.highPriority && 'priority' }
- 類似地,priority
類別會於 highPriority
為 true 時套用。當使用者勾選 High Priority 框儲存後,文字呈不同顏色。
若要傳入物件為類別綁定,寫法是::class="{{ priority: item.highPriority, strikeout: item.purchased }}"
import { ChangeDetectionStrategy, Component, computed, signal } from '@angular/core';
type Item = { id: number; label: string; purchased: boolean; highPriority: boolean };
@Component({
selector: 'app-shopping-cart',
imports: [],
template: `
<ul>
@for (item of items(); track item.id) {
@let itemClasses =
{
priority: item.highPriority,
strikeout: item.purchased,
};
<div class="list-item">
<li [class]="itemClasses" (click)="togglePurchase(item)">
{{ item.id }} - {{ item.label }}
</li>
</div>
}
</ul>
`,
changeDetection: ChangeDetectionStrategy.OnPush,
})
export class ShoppingCartComponent {
items = signal<Item[]>([]);
newItem = signal('');
newItemHighPriority = signal(false);
togglePurchase(item: Item) {
this.items.update((items) =>
items.map((element) => (element.id === item.id ? { ...element, purchased: !element.purchased } : element))
);
this.newItem.set('');
this.newItemHighPriority.set(false);
}
}
Angular 引入了 ``@let` 語法來在模板中建立臨時變數:
@let itemClasses = {
priority: item.highPriority,
strikeout: item.purchased,
};
當 item.highPriority
為 true 時,itemClasses
是 { priority }
,當 item.purchased
為 true 時,itemClasses
是 { strikeout }
。兩者都為 true 時,合併為 { priority, strikeout }
。
類似屬性綁定,使用方括弧語法綁定類別:
[class]="itemClasses"`
這樣會把 itemClasses
傳入 <li> 元素的 CSS 類別。
當 newItemHighPriority
是 true 時,High Priority 勾選框的 font-weight
樣式設為粗體(bold),否則為正常(normal):
{ font-weight: newItemHighPriority ? 'bold': 'normal' }
- 此樣式物件綁定給 style
屬性,生效為行內樣式。
<script setup lang="ts">
import { Icon } from '@iconify/vue'
import { ref, computed } from 'vue'
const newItemHighPriority = ref(false)
const saveItem = () => { /* 同前邏輯 */ }
</script>
<template>
<form v-if="isEditing" @submit.prevent="saveItem">
<label>
<input type="checkbox" v-model="newItemHighPriority" />
<span :style="{ 'font-weight': newItemHighPriority ? 'bold' : 'normal' }">
High Priority</span
>
</label>
</form>
</template>
當 newItemHighPriority
為 true 時,High Priority 勾選框字體粗體 (bold),否則為正常 (normal):
style:font-weight={ newItemHighPriority ? 'bold': 'normal' }
<script lang="ts">
import Icon from '@iconify/svelte';
let newItemHigherPriority = $state(false);
async function handleSubmit(event: SubmitEvent) {
/* 同前邏輯 */
}
</script>
<form method="POST" onsubmit={handleSubmit}>
<label>
<input id="higherPriority" name="higherPriority" type="checkbox" bind:checked={newItemHigherPriority}
/>
<span style:font-weight={newItemHigherPriority ? 'bold' : 'normal'}> Higher Priority</span>
</label>
</form>
當 newItemHighPriority
信號值為 true,High Priority 勾選框的 font-weight 樣式變為粗體 (bold),否則為正常 (normal)。
使用方括弧語法綁定樣式屬性:
[style.fontWeight]="newItemHighPriority ? 'bold': 'normal'"
Angular 使用 camelcase 命名,將 font-weight
轉為 fontWeight
。
import { ChangeDetectionStrategy, Component, computed, signal } from '@angular/core';
import { FormsModule } from '@angular/forms';
@Component({
selector: 'app-shopping-cart',
imports: [FormsModule],
template: `
<form (ngSubmit)="saveItem()">
<label>
<input type="checkbox" [(ngModel)]="newItemHighPriority" name="newItemHighPriority" />
<span [style.fontWeight]="newItemHighPriority() ? 'bold' : 'normal'"> High Priority</span>
</label>
</form>
`,
changeDetection: ChangeDetectionStrategy.OnPush,
})
export class ShoppingCartComponent {
newItemHighPriority = signal(false);
saveItem() { /* 同前邏輯 */ }
}